#include "TextureProxyShader.h"
#include <cstdlib>
#include "CoordinateSystemShader.h"
#include "Renderer.h"
#include "ShaderProgram.h"
/**
派生自 CoordinateSystemShader
对其进行了加强，使用了 木头纹理来进行渲染
*/
TextureProxyShader::TextureProxyShader()
    : TextureProxyShader(
          {
              // positions                     // texture
              // coords
              0.5f,  0.5f,  0.0f, 1.0f, 1.0f, // top right
              0.5f,  -0.5f, 0.0f, 1.0f, 0.0f, // bottom right
              -0.5f, -0.5f, 0.0f, 0.0f, 0.0f, // bottom left
              -0.5f, 0.5f,  0.0f, 0.0f, 1.0f  // top left
          },
          {0, 1, 2, 0, 2, 3},
          [](const string& vectexSrc, const string& fragmentSrc)
          { return new CoordinateSystemShader(vectexSrc, fragmentSrc); })
{
}


TextureProxyShader::TextureProxyShader(vector<float> vertices,
                                       vector<int> indices, function<ShaderProgram*(const string&,const string&)>lambda)
{
    const string vertexShaderSource = "#version 330 core            \n\
            layout ( location = 0 ) in vec3 aPos;           \n\
            layout ( location = 1 ) in vec2 textCoordAttr;  \n\
            out vec2 textureCoord;                          \n\
            uniform   mat4 model;                           \n\
            uniform   mat4 view;                            \n\
            uniform   mat4 projection;                      \n\
            void    main(){                                 \n\
                gl_Position = projection * view * model * vec4(aPos,1.0);      \n\
                textureCoord = textCoordAttr;                                   \n\
        }\0";
    const string fragmentShaderSource = "#version 330 core        \n\
                                    out vec4 FragColor;     \n\
                                    in vec2 textureCoord;   \n\
                                    uniform sampler2D text; \n\
                                    void main(){            \n\
                                        FragColor = texture(text,textureCoord);    \n\
        }\0";

    target = lambda(vertexShaderSource, fragmentShaderSource);
    // new CoordinateSystemShader(vertexShaderSource, fragmentShaderSource);
    this->vertices = vertices;
    this->indices = indices;
}



unsigned int TextureProxyShader::createShaderProgram()
{
    shaderProgram = target->createShaderProgram();

    textureLocation = glGetUniformLocation(shaderProgram, "text");
    if (textureLocation == -1)
    {
        cout << "failed to get uniform text's Location" << endl;
    }
    return shaderProgram;
}

void TextureProxyShader::prepareVAO()
{

    // 1、创建EBO对象
    unsigned int EBO;
    glGenBuffers(1, &EBO);

    // 2、绑定EBO
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);

    // 3、拷贝顶点顺序索引到EBO中
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->indices.size() * sizeof(int),
                 this->indices.data(), GL_STATIC_DRAW);

    unsigned int VBO;
    glGenBuffers(1, &VBO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(float) * this->vertices.size(),
                 this->vertices.data(), GL_STATIC_DRAW);

    // 传送四边形顶点
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float),
                          (void*)0);
    glEnableVertexAttribArray(0);

    // 传送纹理坐标
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float),
                          (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);

    textureId = Renderer::loadTexture(
        "./resources/wooden_container_texture.jpg", GL_TEXTURE0, GL_RGB);

    glUseProgram(shaderProgram);

    /**
    * 显式告诉着色器使用哪个纹理单元，确保跨平台/驱动的可靠性。
    location of a texture 被叫做 texture unit
    texture unit 可以取以下的值
    GL_TEXTURE0、GL_TEXTURE1、GL_TEXTURE2 ... GL_TEXTURE15
    使用 glUniform1i 可以把 texture unit 绑定到 Fragment Shader 的 uniform
    sampler2D 上 其中 一个 Fragment Shader 中可以有多个 uniform sampler2D
    */
    glUniform1i(textureLocation, 0);
}

void TextureProxyShader::update()
{
    target->update();
    glActiveTexture(GL_TEXTURE0); // 明确指定纹理单元，避免依赖默认状态
    glBindTexture(GL_TEXTURE_2D, textureId);
}

void TextureProxyShader::render()
{

    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
}

TextureProxyShader::~TextureProxyShader() { delete target; }
